package com.aaa.vegetablemarketexpress.shiro;

import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;

import java.util.LinkedHashMap;
import java.util.Properties;

/**
 * @FileName: SpringShiroConfig
 * @Description: spring整合shiro配置
 * @Author: qxh
 * @CreateTime: 2025/9/26 17:13
 * @Version: 1.0.0
 */
@Configuration// 相当于spring-shiro-config.xml <beans></beans>
public class SpringShiroConfig {
    /**
     * ShiroFilterFactoryBean  shiro过滤工厂类
     *   所有请求都走这个shiroFilter
     *  配置过滤所有请求，可以配置不同权限URL
     * @return
     */
    @Bean// //<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    public ShiroFilterFactoryBean shiroFilterFactory(){
        //实例化对象
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //设置SecurityManager  过滤到的所有请求肯定要做认证或者授权，这些功能交给SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager());
        //未认证跳转的（登录）页面路径
        shiroFilterFactoryBean.setLoginUrl("/html/front/login.html");
        //认证成功后跳转的页面   登录成功后，我们当前项目使用js跳转到首页，所以这个配置用不上
        //shiroFilterFactoryBean.setSuccessUrl("/html/index.html");
        //跳转到未授权的错误提示界面（认证成功后，访问了不该访问的资源）
        shiroFilterFactoryBean.setUnauthorizedUrl("/html/unauthorized.html");
        //实例化map，map存放过滤链的地址的  LinkedHashMap  可以按照放入顺序排序  不能使用hashmap，因为无序
        LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        //当请求地址中含有admin  authc 必须认证（必须登录）才能访问含有admin的连接并且必须具备admin角色
        //authc = AuthenticatingFilter
        //             http://localhost:8080/admin/queryById?id=1
        //             http://localhost:8080/admin/add
        //             http://localhost:8080/admin/update
        //filterChainDefinitionMap.put("/admin/**", "authc,perms[admin]");

        //当请求地址中含有docs  authc 必须认证（必须登录）才能访问含有admin的连接并且必须具备document:read权限  //authc = AuthenticatingFilter
        //             http://localhost:8080/admin/queryById?id=1
        //             http://localhost:8080/admin/add
        //             http://localhost:8080/admin/update  //perms =permission 权限
        //filterChainDefinitionMap.put("/docs/**", "authc,perms[document:read]");

        //配置放行的URL   配置anon = AnonymousFilter 匿名过滤器 配置后不需要登录就可以访问资源
        //放行以.js结尾的
        //filterChainDefinitionMap.put("/js/**","anon");
        filterChainDefinitionMap.put("/**/*.js", "anon");
        //anon= AnonymousFilter
        filterChainDefinitionMap.put("/**.ttf","anon");  //anon= AnonymousFilter
        filterChainDefinitionMap.put("/**.woff","anon");  //anon= AnonymousFilter
        filterChainDefinitionMap.put("/css/**","anon");  //anon= AnonymousFilter
        filterChainDefinitionMap.put("/images/**","anon");  //anon= AnonymousFilter
        // filterChainDefinitionMap.put("/**.jpg","anon");  //anon= AnonymousFilter
        //filterChainDefinitionMap.put("/**.jpeg","anon");  //anon= AnonymousFilter
        filterChainDefinitionMap.put("/html/login.html","anon");  //anon= AnonymousFilter
        filterChainDefinitionMap.put("/user/login","anon");  //anon= AnonymousFilter
        //... 还需要放行，继续写


        //配置登出    /user11/logout 该地址可以随便写，只要后面是logout
        // 过滤器就会处理退出操作  注销session 跳转到登录界面
        filterChainDefinitionMap.put("/**/user/logout","logout");//logout = LogoutFilter
        //配置所有请求必须认证（必须登录）才能访问
        filterChainDefinitionMap.put("/**","authc");//authc = AuthenticatingFilter
        ////配置shiro过滤链定义
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        //返回对象
        return shiroFilterFactoryBean;



    }
    /**
     * DefaultWebSecurityManager  安全管理器 shiro核心概念
     * @return
     */
    @Bean
    public DefaultWebSecurityManager securityManager(){
        //实例化对象
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        //设置realm   SecurityManager做认证和授权需要安全数据，通过realm获取，所以要配置realm
        defaultWebSecurityManager.setRealm(myCustomRealm());
        //返回对象
        return defaultWebSecurityManager;
    }
    /**
     * MyCustomRealm  自定义Realm
     * @return
     */
    @Bean
    public MyCustomRealm myCustomRealm(){
        //实例化对象
        MyCustomRealm myCustomRealm = new MyCustomRealm();
        //设置Realm设置加密算法
        myCustomRealm.setCredentialsMatcher(credentialsMatcher());
        //返回对象
        return myCustomRealm;
    }
    /**
     * HashedCredentialsMatcher  配置加密算法
     * @return
     */
    @Bean
    public HashedCredentialsMatcher credentialsMatcher(){
        //实例化对象
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        //设置加密算法
        hashedCredentialsMatcher.setHashAlgorithmName("SHA-512");
        //设置加密次数
        hashedCredentialsMatcher.setHashIterations(1024);
        //返回对象
        return hashedCredentialsMatcher;
    }
    /**
     * AOP配置   想让在业务方法执行之前，加上是否拥有角色或者权限判断
     * @return
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator =
                new DefaultAdvisorAutoProxyCreator();// <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);//<property name="proxyTargetClass" value="true"></property>
        return defaultAdvisorAutoProxyCreator;


    }
    /**
     *
     * 让业务方法支持授权属性注解  @RequiresRoles   @RequiresPermissions
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor =
                new AuthorizationAttributeSourceAdvisor();//<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        //设置安全管理器 设置与SecurityManager的关联，因为最终判断是否具有权限，都是SecurityManager来完成
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
        return authorizationAttributeSourceAdvisor;

    }
    /**
     * 配置异常处理器必须是HandlerExceptionResolver接口实现类
     * @return
     */
    @Bean
    public SimpleMappingExceptionResolver simpleMappingExceptionResolver(){
        SimpleMappingExceptionResolver simpleMappingExceptionResolver =
                new SimpleMappingExceptionResolver();//<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        //设置异常映射 配置当出现未授权异常时，跳转地址，只依赖shiro的配置不会跳转
        Properties properties = new Properties();//<property name="exceptionMappings">
        properties.setProperty("org.apache.shiro.authz.UnauthorizedException","/html/unauthorized");
        simpleMappingExceptionResolver.setExceptionMappings(properties);
        return simpleMappingExceptionResolver;

    }
}
